/* //////////////////////////////////////////////////////////////////////////
//
//               INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in accordance with the terms of that agreement.
//        Copyright (c) 2005-2008 Intel Corporation. All Rights Reserved.
//
*/

#include "umc_defs.h"

#if defined (UMC_ENABLE_H261_VIDEO_DECODER)

#include "h261decoder.h"

static Ipp32u _ShowBits(H261DEC_STATE* dec_state, Ipp32s n)
{
    Ipp8u* ptr = dec_state->bufptr;
    Ipp32u tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] <<  8) | (ptr[3]);
    tmp <<= dec_state->bitoff;
    tmp >>= 32 - n;
    return tmp;
}

static void _FlushBits(H261DEC_STATE* dec_state, Ipp32s n)
{
    n = n + dec_state->bitoff;
    dec_state->bufptr += n >> 3;
    dec_state->bitoff = n & 7;
}

static Ipp32u _GetBits(H261DEC_STATE* dec_state, Ipp32s n)
{
    Ipp8u* ptr = dec_state->bufptr;
    Ipp32u tmp = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] <<  8) | (ptr[3]);
    tmp <<= dec_state->bitoff;
    tmp >>= 32 - n;
    n = n + dec_state->bitoff;
    dec_state->bufptr += n >> 3;
    dec_state->bitoff = n & 7;
    return tmp;
}


Ipp32s getPictureHeader(H261DEC_STATE* dec_state)
{
  Ipp32u code;

  // PSC
  code = _GetBits(dec_state, 20);
  if (code != 16)
    return 1;

  // decode TR
  code = _GetBits(dec_state, 5);

  // set picture time
  if (code < dec_state->tr)
    code += 32;
  if (dec_state->tr < 32)
    dec_state->time += code - dec_state->tr;
  dec_state->tr = (Ipp8u)(code & 0x1F);

  // decode PTYPE
  code = _GetBits(dec_state, 6);

  // Split screen indicator is ignored
//  if (code & 0x20) {
//    ErrMsg("Split Screen Indicator not supported");
//    return -1;
//  }

  // Document camera indicator is ignored
//  if (code & 0x10) {
//    ErrMsg("Document Camera Indicator not supported");
//    return -1;
//  }

  // Freeze Picture Release bit is ignored
//  if (code & 0x8) {
//    ErrMsg("Freeze Picture Release not supported");
//    return -1;
//  }

  // Source format
  if (code & 0x4) {
    dec_state->picture_format = 1;  // CIF
    dec_state->picture_width = 352;
    dec_state->picture_height = 288;
    dec_state->numgob = 12;
  } else {
    dec_state->picture_format = 0;  // QCIF
    dec_state->picture_width = 352/2;
    dec_state->picture_height = 288/2;
    dec_state->numgob = 3;
  }

//  Still image bit is ignored - Annex D not supported
//  if ((code & 0x2) == 0) {
//    ErrMsg("Still Image Mode not supported");
//    return -1;
//  }
  // bit 6 of PTYPE is spare

  while (_GetBits(dec_state, 1)) { // extra insertion information (PEI)
    _FlushBits(dec_state, 8); // PSPARE
  }

  return 0;
} // getPictureHeader()

#define H261_LIMIT_MV(bx, by, mvx, mvy, width, height) \
  if (mvx < -(bx)) \
    mvx = -(bx); \
  if (mvx > (width) - (bx) - 16)  \
    mvx = (width) - (bx) - 16; \
  if (mvy < -(by)) \
    mvy = -(by); \
  if (mvy > (height) - (by) - 16)  \
    mvy = (height) - (by) - 16; \

static void reconstruct(Ipp32s bx, Ipp32s by, Ipp32s mvx, Ipp32s mvy, Ipp32s filter, H261DEC_STATE* dec_state)
{
  Ipp8u* src;
  Ipp8u* dst;
  Ipp32s i;
  Ipp32s lx = dec_state->picture_width;

  H261_LIMIT_MV(bx, by, mvx, mvy, dec_state->picture_width, dec_state->picture_height)

  /* Y */
  src = dec_state->refPic[0] + lx * (by + mvy) + bx + mvx;
  dst = dec_state->curPic[0] + lx * by + bx;

  if (filter) {
    Ipp8u *dblock, *sblock;
    for (i = 0; i < 4; i++) {
      dblock = dst + (i & 2)*4*lx + (i & 1)*8;
      sblock = src + (i & 2)*4*lx + (i & 1)*8;
      ippiFilter8x8_H261_8u_C1R(sblock, lx, dblock, lx);
    }
  } else {
    ippiCopy16x16_8u_C1R(src, lx, dst, lx);
  }

  /* Chroma */
  lx  >>= 1;
  bx >>= 1;
  by >>= 1;
  mvx /= 2;   // truncate towards zero, can be negative
  mvy /= 2;

  src = dec_state->refPic[1] + lx * (by + mvy) + bx + mvx;
  dst = dec_state->curPic[1] + lx * by + bx;

  if (filter)
    ippiFilter8x8_H261_8u_C1R(src, lx, dst, lx);
  else
    ippiCopy8x8_8u_C1R(src, lx, dst, lx);

  src = dec_state->refPic[2] + lx * (by + mvy) + bx + mvx;
  dst = dec_state->curPic[2] + lx * by + bx;
  if (filter)
    ippiFilter8x8_H261_8u_C1R(src, lx, dst, lx);
  else
    ippiCopy8x8_8u_C1R(src, lx, dst, lx);

} // reconstruct()


static Ipp32s fillBlock(Ipp32s bx, Ipp32s by, Ipp32s i, Ipp32s quant, H261DEC_STATE* dec_state)
{
  __ALIGN16(Ipp16s, coeffs, 64);
  Ipp32s    step;
  Ipp8u*    pDst;
  IppStatus status;
  Ipp32s iLNZ;
  Ipp32s picture_width = dec_state->picture_width;

#if 0
  {
    __ALIGN16(Ipp16s, coeffsZ, 64);
    status = ippiDecodeCoeffsIntra_H261_1u16s(&dec_state->bufptr, &dec_state->bitoff,
                                              coeffsZ, &iLNZ, -1);
    if (status != ippStsNoErr)
      return -1;
    status = ippiQuantInvIntra_H263_16s_C1I(coeffsZ, iLNZ, quant, 0, 0);
    if (status != ippStsNoErr)
      return -1;
    status = ippiScanInv_16s_C1(coeffsZ, coeffs, iLNZ, IPPVC_SCAN_ZIGZAG);
  }
#else

  status = ippiReconstructCoeffsIntra_H261_1u16s(&dec_state->bufptr, &dec_state->bitoff,
                                                 coeffs, &iLNZ, quant);
#endif
  if (status != ippStsNoErr)
    return -1;

  if (i > 3) {
    step = picture_width >> 1;
    bx >>= 1;
    by >>= 1;
    pDst = dec_state->curPic[i-3] + step*by + bx;
  } else {
    step = picture_width;
    pDst = dec_state->curPic[0] + picture_width*(by + (i & 2)*4) + bx + (i & 1)*8;
  }

  ippiDCT8x8Inv_16s8u_C1R(coeffs, pDst, step);

  return 0;
} // fillBlock()


static Ipp32s reconBlock(Ipp32s bx, Ipp32s by, Ipp32s i, Ipp32s quant, H261DEC_STATE* dec_state)
{
  __ALIGN16(Ipp16s, coeffs, 64);
  Ipp32s    step;
  Ipp8u*    pSrcDst;
  IppStatus status = ippStsErr;
  Ipp32s    iLNZ;
  Ipp32s    picture_width = dec_state->picture_width;

#if 0
  {
    __ALIGN16(Ipp16s, coeffsZ, 64);
    status = ippiDecodeCoeffsInter_H261_1u16s(&dec_state->bufptr, &dec_state->bitoff,
                                              coeffsZ, &iLNZ, -1);
    if (status != ippStsNoErr)
      return -1;
    status = ippiQuantInvInter_H263_16s_C1I(coeffsZ, iLNZ, quant, 0);
    if (status != ippStsNoErr)
      return -1;
    status = ippiScanInv_16s_C1(coeffsZ, coeffs, iLNZ, IPPVC_SCAN_ZIGZAG);
  }
#else
  status = ippiReconstructCoeffsInter_H261_1u16s(&dec_state->bufptr, &dec_state->bitoff,
                                                 coeffs, &iLNZ, quant);
#endif
  if (status != ippStsNoErr)
    return -1;

  if ((iLNZ < 5) && (!coeffs[16]))
    ippiDCT8x8Inv_2x2_16s_C1I(coeffs);
  else if ((iLNZ < 10) || ((iLNZ < 14) && (!coeffs[32])) ||
    ((iLNZ < 19) && (!(coeffs[32] | coeffs[4] | coeffs[5] | coeffs[12]))))
    ippiDCT8x8Inv_4x4_16s_C1I(coeffs);
  else
    ippiDCT8x8Inv_16s_C1I(coeffs);

  if (i > 3) {
    step = picture_width >> 1;
    bx >>= 1;
    by >>= 1;
    pSrcDst = dec_state->curPic[i-3] + step*by + bx;
  } else {
    step = picture_width;
    pSrcDst = dec_state->curPic[0] + picture_width*(by + (i & 2)*4) + bx + (i & 1)*8;
  }
  ippiAdd8x8_16s8u_C1IRS(coeffs, 16, pSrcDst, step);

  return 0;
} // reconBlock()


/*-------------------------------------------------------------*/

typedef struct {
  Ipp16u val;
  Ipp16u len;
} H261_vlc;

#define VLC_ERR   -1

static const H261_vlc mba_tab1[15] =
{
  {7,5}, {6,5}, {5,4}, {5,4}, {4,4}, {4,4}, {3,3}, {3,3}, {3,3}, {3,3},
  {2,3}, {2,3}, {2,3}, {2,3}, {1,1}
};

static const H261_vlc mba_tab2[46] =
{
  {21,6}, {20,6}, {19,6}, {18,6}, {17,6}, {16,6},
  {15,4}, {15,4}, {15,4}, {15,4}, {14,4}, {14,4}, {14,4}, {14,4},
  {13,4}, {13,4}, {13,4}, {13,4}, {12,4}, {12,4}, {12,4}, {12,4},
  {11,4}, {11,4}, {11,4}, {11,4}, {10,4}, {10,4}, {10,4}, {10,4},
  {9, 3}, {9, 3}, {9, 3}, {9, 3}, {9, 3}, {9, 3}, {9, 3}, {9, 3},
  {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3},
};

static Ipp32s dec_MBA(H261DEC_STATE* dec_state)
{
  Ipp32u code;
  Ipp32s mba, len;
  H261_vlc vlc;

  code = _ShowBits(dec_state, 5);
  if (code >= 16) {
    _FlushBits(dec_state, 1);
    mba = 1;
  } else if (code > 1) {
    vlc = mba_tab1[code - 2];
    mba = vlc.val;
    len = vlc.len;
    _FlushBits(dec_state, len);
  } else {
    _FlushBits(dec_state, 4);
    code = _ShowBits(dec_state, 7);
    if ((code >> 1) >= 18) {
      vlc = mba_tab2[(code >> 1) - 18];
      mba = vlc.val;
      len = vlc.len;
    } else {
      len = 7;
      if (code >= 16) {
        mba = 57 - code;
      } else
//        mba = (code == 15) ? IPPVC_MB_STUFFING : VLC_ERR;
        mba = -1;
    }
    _FlushBits(dec_state, len);
  }
  return mba;
}

/*-------------------------------------------------------------*/

#define MTYPE_INTRA   1
#define MTYPE_MQUANT  2
#define MTYPE_MVD     4
#define MTYPE_TCOEFF  8
#define MTYPE_FIL     16

static const Ipp8u mtype_tab[10] =
{
  MTYPE_TCOEFF,
  MTYPE_TCOEFF | MTYPE_MVD | MTYPE_FIL,
  MTYPE_MVD | MTYPE_FIL,
  MTYPE_INTRA, // | MTYPE_TCOEFF,
  MTYPE_TCOEFF | MTYPE_MQUANT,
  MTYPE_TCOEFF | MTYPE_MQUANT | MTYPE_MVD | MTYPE_FIL,
  MTYPE_INTRA  | MTYPE_MQUANT, // | MTYPE_TCOEFF,
  MTYPE_TCOEFF | MTYPE_MVD,
  MTYPE_MVD,
  MTYPE_TCOEFF | MTYPE_MQUANT | MTYPE_MVD
};

static Ipp32s dec_MTYPE(H261DEC_STATE* dec_state)
{
  Ipp32u code;
  Ipp32s mtype;
  Ipp32s i;

  code = _ShowBits(dec_state, 10);
  for (i = 0; i < 10; i++) {
    if (code & (512 >> i)) break;
  }

  if (i > 9) return VLC_ERR;
  mtype = mtype_tab[i];
  _FlushBits(dec_state, i+1);

  return mtype;
}

/*-------------------------------------------------------------*/

static const H261_vlc mvd_tab1[14] =
{
  {3,5}, {29,5}, {2,4}, {2,4}, {30,4}, {30,4},
  {1,3}, {1,3}, {1,3}, {1,3}, {31,3}, {31,3}, {31,3}, {31,3}
};

static const H261_vlc mvd_tab2[103] =
{
  {16,11}, {15,11}, {17,11}, {14,11}, {18,11}, {13,11}, {19,11}, {12,11},
  {20,11}, {11,11}, {21,11}, {10,10}, {10,10}, {22,10}, {22,10},
  {9,10}, {9,10}, {23,10}, {23,10}, {8,10}, {8,10}, {24,10}, {24,10},
  {7,8}, {7,8}, {7,8}, {7,8}, {7,8}, {7,8}, {7,8}, {7,8},
  {25,8}, {25,8}, {25,8}, {25,8}, {25,8}, {25,8}, {25,8}, {25,8},
  {6,8}, {6,8}, {6,8}, {6,8}, {6,8}, {6,8}, {6,8}, {6,8},
  {26,8}, {26,8}, {26,8}, {26,8}, {26,8}, {26,8}, {26,8}, {26,8},
  {5,8}, {5,8}, {5,8}, {5,8}, {5,8}, {5,8}, {5,8}, {5,8},
  {27,8}, {27,8}, {27,8}, {27,8}, {27,8}, {27,8}, {27,8}, {27,8},
  {4,7}, {4,7}, {4,7}, {4,7}, {4,7}, {4,7}, {4,7}, {4,7},
  {4,7}, {4,7}, {4,7}, {4,7}, {4,7}, {4,7}, {4,7}, {4,7},
  {28,7}, {28,7}, {28,7}, {28,7}, {28,7}, {28,7}, {28,7}, {28,7},
  {28,7}, {28,7}, {28,7}, {28,7}, {28,7}, {28,7}, {28,7}, {28,7}
};

static Ipp32s dec_MVD(H261DEC_STATE* dec_state)
{
  Ipp32u code;
  Ipp32s mvd, len;
  H261_vlc vlc;

  code = _ShowBits(dec_state, 11);
  if (code & 1024) {
    mvd = 0;
    len = 1;
  } else if ((code >> 6) >=  2) {
    vlc = mvd_tab1[(code >> 6) - 2];
    mvd = vlc.val;
    len = vlc.len;
  } else if (code >= 25) {
    vlc = mvd_tab2[code - 25];
    mvd = vlc.val;
    len = vlc.len;
  } else
    return VLC_ERR;

  _FlushBits(dec_state, len);

  return mvd;
}


/*-------------------------------------------------------------*/

static const Ipp8u cbp_tab1[64] =
{
  34, 18, 10, 6, 33, 17, 9, 5, 63, 63, 3, 3,
  36, 36, 24, 24, 62, 62, 62, 62, 2, 2, 2, 2,
  61, 61, 61, 61, 1, 1, 1, 1, 56, 56, 56, 56,
  52, 52, 52, 52, 44, 44, 44, 44, 28, 28, 28, 28,
  40, 40, 40, 40, 20, 20, 20, 20, 48, 48, 48, 48,
  12, 12, 12, 12
};

static const Ipp8s cbp_tab2[64] =
{
  VLC_ERR, VLC_ERR, 39, 27, 59, 55, 47, 31,
  58, 58, 54, 54, 46, 46, 30, 30, 57, 57, 53, 53,
  45, 45, 29, 29, 38, 38, 26, 26, 37, 37, 25, 25,
  43, 43, 23, 23, 51, 51, 15, 15, 42, 42, 22, 22,
  50, 50, 14, 14, 41, 41, 21, 21, 49, 49, 13, 13,
  35, 35, 19, 19, 11, 11, 7, 7
};

static Ipp32s dec_CBP(H261DEC_STATE* dec_state)
{
  Ipp32u code;
  Ipp32s val, len, c4;
  code = _ShowBits(dec_state, 9);

  c4 = code >> 5;
  if (c4 >= 10) {
    if (c4 >= 14) {
      val = 60;
      len = 3;
    } else {
      val = 1 << (15 - c4);
      len = 4;
    }
  } else if (c4 > 1) {
    val = cbp_tab1[(code >> 2) - 16];
    len = (c4 > 3) ? 5 : (9 - c4);
  } else {
    val = cbp_tab2[code];
    len = (code > 7) ? 8 : 9;
  }
  _FlushBits(dec_state, len);
  return val;
}

static void copy_GOBs(H261DEC_STATE* dec_state, Ipp32s gobS, Ipp32s gobE, Ipp32s gob_step)
{
  Ipp32s gob;
  Ipp32s xpos, ypos;
  IppiSize roiY, roiC;
  Ipp32s offY, offC;

  roiY.height = 48;
  roiC.height = 24;
  roiY.width = 176;
  roiC.width = roiY.width >> 1;

  for (gob = gobS; gob < gobE; gob += gob_step) {
    xpos = (gob & 1) ?  0 : 176;
    ypos = ((gob - 1) >> 1) * 3 * 16;

    offY = ypos * dec_state->picture_width + xpos;
    offC = (ypos * dec_state->picture_width >> 2) + (xpos >> 1);

    ippiCopy_8u_C1R(dec_state->refPic[0] + offY, dec_state->picture_width,
      dec_state->curPic[0] + offY, dec_state->picture_width, roiY);
    ippiCopy_8u_C1R(dec_state->refPic[1] + offC, dec_state->picture_width >> 1,
      dec_state->curPic[1] + offC, dec_state->picture_width >> 1, roiC);
    ippiCopy_8u_C1R(dec_state->refPic[2] + offC, dec_state->picture_width >> 1,
      dec_state->curPic[2] + offC, dec_state->picture_width >> 1, roiC);
  }
}

static void copy_Macroblocks(H261DEC_STATE* dec_state, Ipp32s mbaS, Ipp32s nmbs, Ipp32s xpos, Ipp32s ypos)
{
  Ipp32s w;
  IppiSize roiY, roiC;
  Ipp32s mbxpos, mbypos;
  Ipp32s offY, offC, bx, by;

  mbxpos = mbaS % 11;
  mbypos =  mbaS / 11;
  roiY.height = 16;
  roiC.height = 8;

  if (nmbs > 33 - mbaS)
    nmbs = 33 - mbaS; /* error or end of stream */

  while (nmbs > 0) {
    bx = 16 * (mbxpos + xpos);
    by = 16 * (mbypos + ypos);
    offY = by * dec_state->picture_width + bx;
    offC = (by * dec_state->picture_width >> 2) + (bx >> 1);

    w = nmbs > (11 - mbxpos) ? (11 - mbxpos) : nmbs;
    nmbs -= w;
    roiY.width = w*16;
    roiC.width = roiY.width >> 1;

    ippiCopy_8u_C1R(dec_state->refPic[0] + offY, dec_state->picture_width,
      dec_state->curPic[0] + offY, dec_state->picture_width, roiY);
    ippiCopy_8u_C1R(dec_state->refPic[1] + offC, dec_state->picture_width >> 1,
      dec_state->curPic[1] + offC, dec_state->picture_width >> 1, roiC);
    ippiCopy_8u_C1R(dec_state->refPic[2] + offC, dec_state->picture_width >> 1,
      dec_state->curPic[2] + offC, dec_state->picture_width >> 1, roiC);

    mbxpos = 0;
    mbypos++;
  }
}

static Ipp32s find_GBSC(H261DEC_STATE* dec_state, Ipp32u *outCode)
{
  Ipp32s end_of_frame = 0;
  Ipp32u code = *outCode;
  for (;;) {
    while (dec_state->bufptr[1] != 0) {
      dec_state->bufptr++;
      if (dec_state->buflen - (dec_state->bufptr - dec_state->buffer) < 3) {
        end_of_frame = 1;
        break;
      }
    }
    if (end_of_frame)
      break;
    for (dec_state->bitoff = 1; dec_state->bitoff < 8; dec_state->bitoff++) {
      code = _ShowBits(dec_state, 16);
      if (code == 1)
        break;
    }
    if (code != 1) {
      dec_state->bufptr++;
      dec_state->bitoff = 0;
      code = _ShowBits(dec_state, 16);
    }

    if (dec_state->bitoff + 20 > (dec_state->buflen - (dec_state->bufptr - dec_state->buffer)) << 3) {
      end_of_frame = 1;
      break;
    }

    if (code == 1) {
      code = _ShowBits(dec_state, 20);
      break;
    }
  }
  *outCode = code;
  return end_of_frame;
}

/*-------------------------------------------------------------*/

// decoded picture will be in dec_state->refPic
Ipp32s getPicture(H261DEC_STATE* dec_state)
{
  Ipp32s i, numgob, picType = 0, err = 0;
  Ipp32s xpos;
  Ipp32s ypos;
  Ipp32s mbxpos, mbypos;
  Ipp32s gob = 1, prev_gob = 0, gob_step = dec_state->picture_format ? 1 : 2;
  Ipp32s mba = 0, mba_dif;
  Ipp32s mtype;
  Ipp32s cbp;
  Ipp32s mquant;
  Ipp32s r;
  Ipp32s mvx, mvy, mvxd, mvyd;
  Ipp32s bx, by;
  Ipp32u code;
  Ipp32s end_of_frame;
  Ipp32s ret = 0;

  for (numgob = 0; numgob < dec_state->numgob || err == -1; numgob++) {
    err = 0;

    if (dec_state->bitoff + 20 > (dec_state->buflen - (dec_state->bufptr - dec_state->buffer)) << 3)
      break;

    // GBSC
    code = _ShowBits(dec_state, 20);
    if ((code &~ 0xf) != 0x10) {
      end_of_frame = find_GBSC(dec_state, &code);
      if (end_of_frame)
        break;
    }

    if (code == 0x10)
      break;

    _FlushBits(dec_state, 20);

    gob = code & 15;
    if ((gob <= 0) || (gob > 12) || ((dec_state->picture_format == 0) && ((gob > 5) || ((gob & 1) == 0)))) {
      ErrMsg("Invalid GOB number"); // gob numbers 13-15 are reserved for future use
      err = -1;
      continue;
    }

    if (gob - prev_gob - gob_step > 0) { // skipped GOB(s)
      numgob += (gob - prev_gob - gob_step) >> (gob_step - 1);
      copy_GOBs(dec_state, prev_gob + gob_step, gob, gob_step);
    }

    prev_gob = gob;

    mquant = _GetBits(dec_state, 5); // To be used until overriden by any subsequent MQUANT
    if (!mquant) {
      ErrMsg("Invalid GQUANT");
      err = -1;
      continue;
    }
    while (_GetBits(dec_state, 1)) { // extra insertion information (GEI)
      _FlushBits(dec_state, 8); // GSPARE
    }

    xpos = (gob & 1) ?  0 : 11;
    ypos = ((gob - 1) >> 1) * 3;
    mba = 0;
    mvx = mvy = 0;

    for (;;) {
      Ipp32s bits_left = (dec_state->buflen - (dec_state->bufptr - dec_state->buffer)) << 3;

      // 6 bits is minimum MB code length: non-MC MB with in-loop filter on
      for (;;) {
        if (dec_state->bitoff + 6 <= bits_left) {
          code = _ShowBits(dec_state, 6);
          if (code == 0 && (dec_state->bitoff + 11 <= bits_left)) {
            code = _ShowBits(dec_state, 11);
            if (code == 15) {
              _FlushBits(dec_state, 11);
              continue;
            }
          }
        } else
          code = 0;
        break;
      }

      if (code == 0) {  /* start code */
        if (mba < 33) /* need to copy the gob's skipped tail */
          copy_Macroblocks(dec_state, mba, 33 - mba, xpos, ypos);
        break;
      }

      mba_dif = dec_MBA(dec_state);

      if (mba_dif < 0) {
        ErrMsg("Invalid MBA");
        mba++; // macroblock at mba was decoded correctly - need not be copied from prev. frame
        err = -1;
        break;
      }

      if (mba + mba_dif > 33) { /* can happen at the end of stream */
        mba++; // macroblock at mba was decoded correctly
        err = -1;
        break;
      }

      if (mba_dif > 1) /* need to copy the skipped mbs */
        copy_Macroblocks(dec_state, mba, mba_dif - 1, xpos, ypos);

      mba += mba_dif;

      mbxpos = xpos + ((mba - 1) % 11);
      mbypos = ypos + (mba - 1) / 11;
      if ((mba == 12) || (mba == 23) || (mba_dif > 1)) {
        mvx = mvy = 0;
      }
      mtype = dec_MTYPE(dec_state);
      if (mtype < 0) {
        ErrMsg("Invalid MTYPE");
        err = -1;
        break;
      }
      if (mtype & MTYPE_MQUANT) {
        mquant = _GetBits(dec_state, 5); // To be used until overriden by any subsequent MQUANT
        if (!mquant) {
          ErrMsg("Invalid MQUANT");
          err = -1;
          break;
        }
      }
      if (mtype & MTYPE_MVD) {
        mvxd = dec_MVD(dec_state);
        if (mvxd < 0) {
          ErrMsg("Invalid horizontal MV");
          err = -1;
          break;
        }
        mvyd = dec_MVD(dec_state);
        if (mvyd < 0) {
          ErrMsg("Invalid vertical MV");
          err = -1;
          break;
        }
        mvx += mvxd;
        if (mvx > 16) // MV range is [-15,15], (mv==16) implies an error in the stream
          mvx -= 32;
        mvy += mvyd;
        if (mvy > 16)
          mvy -= 32;
      } else {
        mvx = mvy = 0;
      }

      if (mtype & MTYPE_INTRA)
        cbp = 63;
      else if (mtype & MTYPE_TCOEFF) {
        cbp = dec_CBP(dec_state);
        if (cbp < 0) {
          ErrMsg("Invalid CBP");
          err = -1;
          break;
        }
      } else
        cbp = 0;

      bx = 16 * mbxpos;
      by = 16 * mbypos;

      if (!(mtype & MTYPE_INTRA)) {
        picType = 1;
        reconstruct(bx, by, mvx, mvy, mtype & MTYPE_FIL, dec_state);
        for (i = 0; i < 6; i++) {
          if (cbp & (32 >> i)) {
            r = reconBlock(bx, by, i, mquant, dec_state);
            if (r < 0) {
              ErrMsg("reconBlock failed");
              err = -1;
              break;
            }
          }
        }
      } else { // intra
        for (i = 0; i < 6; i++) {
          r = fillBlock(bx, by, i, mquant, dec_state);
          if (r < 0) {
            ErrMsg("fillBlock failed");
            err = -1;
            break;
          }
        }
      }
    }
    if (err == -1) {
      copy_Macroblocks(dec_state, mba - 1, 33 - mba + 1, xpos, ypos);
      ret = -1;
    }
  }

  gob = dec_state->picture_format ? 13 : 6;
  if (gob - prev_gob - gob_step > 0)
    copy_GOBs(dec_state, prev_gob + gob_step, dec_state->picture_format ? 13 : 6, gob_step);

//  _SWAP(Ipp8u*, dec_state->curPic[0], dec_state->refPic[0]);
//  _SWAP(Ipp8u*, dec_state->curPic[1], dec_state->refPic[1]);
//  _SWAP(Ipp8u*, dec_state->curPic[2], dec_state->refPic[2]);
  _SWAP(Ipp32u, dec_state->mid_cur, dec_state->mid_ref);

  dec_state->picType = picType;
//  return err;
  return ret;
} // getPicture()


Ipp32s initDecoder(H261DEC_STATE *dec_state)
{
//  Ipp32s picture_width, picture_height;
  Ipp32s status;

  dec_state->bufptr = dec_state->buffer;
  dec_state->bitoff = 0;
  status = getPictureHeader(dec_state);
  if (status != 0)
    return status;
  dec_state->bufptr = dec_state->buffer;
  dec_state->bitoff = 0;
  return 0;
} // initDecoder()

#endif // defined (UMC_ENABLE_H261_VIDEO_DECODER)
